package com.example.chamberlainserver.Service.impl;

import com.example.chamberlainserver.Entry.ScheduleAssignment;
import com.example.chamberlainserver.Entry.ShiftTime;
import com.example.chamberlainserver.Entry.User;
import com.example.chamberlainserver.Entry.UserAvailability;
import com.example.chamberlainserver.Service.ScheduleAssignmentService;
import com.example.chamberlainserver.Service.ShiftTimeService;
import com.example.chamberlainserver.Service.UserAvailabilityService;
import com.example.chamberlainserver.Service.UserService;
import com.example.chamberlainserver.dto.PageResult;
import com.example.chamberlainserver.mapper.ScheduleAssignmentMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 排班分配服务实现类
 */
@Service
public class ScheduleAssignmentServiceImpl implements ScheduleAssignmentService {

    @Autowired
    private ScheduleAssignmentMapper scheduleAssignmentMapper;
    
    @Autowired
    private UserService userService;
    
    @Autowired
    private ShiftTimeService shiftTimeService;
    
    @Autowired
    private UserAvailabilityService userAvailabilityService;

    @Override
    public boolean addScheduleAssignment(ScheduleAssignment scheduleAssignment) {
        scheduleAssignment.setId(UUID.randomUUID().toString());
        scheduleAssignment.setCreatedAt(LocalDateTime.now());
        scheduleAssignment.setUpdatedAt(LocalDateTime.now());
        if (scheduleAssignment.getStatus() == null) {
            scheduleAssignment.setStatus("scheduled");
        }
        return scheduleAssignmentMapper.insertScheduleAssignment(scheduleAssignment) > 0;
    }

    @Override
    @Transactional
    public boolean batchAddScheduleAssignment(List<ScheduleAssignment> scheduleAssignmentList) {
        if (scheduleAssignmentList == null || scheduleAssignmentList.isEmpty()) {
            return false;
        }
        
        LocalDateTime now = LocalDateTime.now();
        for (ScheduleAssignment scheduleAssignment : scheduleAssignmentList) {
            scheduleAssignment.setId(UUID.randomUUID().toString());
            scheduleAssignment.setCreatedAt(now);
            scheduleAssignment.setUpdatedAt(now);
            if (scheduleAssignment.getStatus() == null) {
                scheduleAssignment.setStatus("scheduled");
            }
        }
        
        return scheduleAssignmentMapper.batchInsertScheduleAssignment(scheduleAssignmentList) > 0;
    }

    @Override
    public ScheduleAssignment getScheduleAssignmentById(String id) {
        ScheduleAssignment scheduleAssignment = scheduleAssignmentMapper.getScheduleAssignmentById(id);
        if (scheduleAssignment != null) {
            loadRelatedData(scheduleAssignment);
        }
        return scheduleAssignment;
    }

    @Override
    public List<ScheduleAssignment> getScheduleAssignmentsByUserId(Integer userId) {
        List<ScheduleAssignment> scheduleAssignments = scheduleAssignmentMapper.getScheduleAssignmentsByUserId(userId);
        
        for (ScheduleAssignment scheduleAssignment : scheduleAssignments) {
            loadRelatedData(scheduleAssignment);
        }
        
        return scheduleAssignments;
    }

    @Override
    public List<ScheduleAssignment> getScheduleAssignmentsByDateRange(LocalDate startDate, LocalDate endDate) {
        List<ScheduleAssignment> scheduleAssignments = scheduleAssignmentMapper.getScheduleAssignmentsByDateRange(startDate, endDate);
        
        for (ScheduleAssignment scheduleAssignment : scheduleAssignments) {
            loadRelatedData(scheduleAssignment);
        }
        
        return scheduleAssignments;
    }

    @Override
    public List<ScheduleAssignment> getScheduleAssignmentsByShiftId(String shiftId) {
        List<ScheduleAssignment> scheduleAssignments = scheduleAssignmentMapper.getScheduleAssignmentsByShiftId(shiftId);
        
        for (ScheduleAssignment scheduleAssignment : scheduleAssignments) {
            loadRelatedData(scheduleAssignment);
        }
        
        return scheduleAssignments;
    }

    @Override
    public List<ScheduleAssignment> getScheduleAssignmentsByUserAndDate(Integer userId, LocalDate scheduleDate) {
        List<ScheduleAssignment> scheduleAssignments = scheduleAssignmentMapper.getScheduleAssignmentsByUserAndDate(userId, scheduleDate);
        for (ScheduleAssignment scheduleAssignment : scheduleAssignments) {
            loadRelatedData(scheduleAssignment);
        }
        return scheduleAssignments;
    }

    @Override
    public boolean updateScheduleAssignment(ScheduleAssignment scheduleAssignment) {
        scheduleAssignment.setUpdatedAt(LocalDateTime.now());
        return scheduleAssignmentMapper.updateScheduleAssignment(scheduleAssignment) > 0;
    }

    @Override
    public boolean deleteScheduleAssignment(String id) {
        return scheduleAssignmentMapper.deleteScheduleAssignmentById(id) > 0;
    }

    @Override
    public boolean updateScheduleAssignmentStatus(String id, String status) {
        return scheduleAssignmentMapper.updateScheduleAssignmentStatus(id, status) > 0;
    }

    @Override
    public PageResult<ScheduleAssignment> getPagedScheduleAssignmentList(Map<String, Object> params) {
        // 查询总记录数
        Long total = scheduleAssignmentMapper.getPagedScheduleAssignmentCount(params);
        
        // 查询数据列表
        List<ScheduleAssignment> scheduleAssignments = scheduleAssignmentMapper.getPagedScheduleAssignmentList(params);
        
        // 为每个记录加载关联数据
        for (ScheduleAssignment scheduleAssignment : scheduleAssignments) {
            loadRelatedData(scheduleAssignment);
        }
        
        Integer current = (Integer) params.getOrDefault("current", 1);
        Integer pageSize = (Integer) params.getOrDefault("pageSize", 10);
        
        return new PageResult<>(current, pageSize, total, scheduleAssignments);
    }

    @Override
    @Transactional
    public List<ScheduleAssignment> generateSmartSchedule(LocalDate startDate, LocalDate endDate, Integer assignedBy) {
        List<ScheduleAssignment> generatedSchedule = new ArrayList<>();
        
        // 获取所有活跃的班次
        List<ShiftTime> activeShifts = shiftTimeService.getActiveShiftTimes();
        if (activeShifts.isEmpty()) {
            return generatedSchedule;
        }
        
        // 遍历日期范围
        LocalDate currentDate = startDate;
        while (!currentDate.isAfter(endDate)) {
            int dayOfWeek = currentDate.getDayOfWeek().getValue(); // 1=Monday, 7=Sunday
            
            // 获取当天可用的用户
            List<UserAvailability> availableUsers = userAvailabilityService.getAvailableUsersByDayOfWeek(dayOfWeek);
            
            if (!availableUsers.isEmpty()) {
                // 为每个班次分配用户
                for (ShiftTime shift : activeShifts) {
                    // 过滤出符合该班次时间要求的用户
                    List<UserAvailability> suitableUsers = availableUsers.stream()
                        .filter(ua -> isUserSuitableForShift(ua, shift))
                        .collect(Collectors.toList());
                    
                    if (!suitableUsers.isEmpty()) {
                        // 简单的轮询分配策略
                        UserAvailability selectedUser = selectUserForShift(suitableUsers, currentDate, shift);
                        
                        ScheduleAssignment assignment = new ScheduleAssignment();
                        assignment.setUserId(selectedUser.getUserId());
                        assignment.setShiftId(shift.getId());
                        assignment.setScheduleDate(currentDate);
                        assignment.setStatus("scheduled");
                        assignment.setCreatedBy(assignedBy != null ? assignedBy : 1);
                        
                        generatedSchedule.add(assignment);
                    }
                }
            }
            
            currentDate = currentDate.plusDays(1);
        }
        
        return generatedSchedule;
    }

    @Override
    public Integer countUserAssignmentsInDateRange(Integer userId, LocalDate startDate, LocalDate endDate) {
        return scheduleAssignmentMapper.countUserAssignmentsInDateRange(userId, startDate, endDate);
    }

    @Override
    public boolean checkScheduleConflict(ScheduleAssignment scheduleAssignment) {
        // 检查同一用户在同一日期是否已有排班
        List<ScheduleAssignment> existingAssignments = scheduleAssignmentMapper.getScheduleAssignmentsByUserAndDate(
                scheduleAssignment.getUserId(), scheduleAssignment.getScheduleDate());
        
        // 如果是更新操作，排除自身
        if (scheduleAssignment.getId() != null) {
            existingAssignments = existingAssignments.stream()
                    .filter(assignment -> !assignment.getId().equals(scheduleAssignment.getId()))
                    .collect(java.util.stream.Collectors.toList());
        }
        
        return !existingAssignments.isEmpty();
    }



    /**
     * 为排班分配加载关联数据
     */
    private void loadRelatedData(ScheduleAssignment scheduleAssignment) {
        if (scheduleAssignment.getUserId() != null) {
            User user = userService.getUserById(scheduleAssignment.getUserId());
            scheduleAssignment.setUser(user);
        }
        
        if (scheduleAssignment.getShiftId() != null) {
            ShiftTime shiftTime = shiftTimeService.getShiftTimeById(scheduleAssignment.getShiftId());
            scheduleAssignment.setShift(shiftTime);
        }
        
        if (scheduleAssignment.getCreatedBy() != null) {
            User creator = userService.getUserById(scheduleAssignment.getCreatedBy());
            scheduleAssignment.setCreator(creator);
        }
    }

    /**
     * 判断用户是否适合某个班次
     */
    private boolean isUserSuitableForShift(UserAvailability userAvailability, ShiftTime shift) {
        // 检查时间是否匹配
        if (userAvailability.getStartTime() != null && userAvailability.getEndTime() != null) {
            return !userAvailability.getStartTime().isAfter(shift.getStartTime()) && 
                   !userAvailability.getEndTime().isBefore(shift.getEndTime());
        }
        return true; // 如果没有具体时间限制，认为适合
    }

    /**
     * 为班次选择用户（简单的轮询策略）
     */
    private UserAvailability selectUserForShift(List<UserAvailability> suitableUsers, LocalDate date, ShiftTime shift) {
        // 这里可以实现更复杂的分配算法，比如考虑工作量平衡、用户偏好等
        // 目前使用简单的轮询策略
        int index = (date.getDayOfYear() + shift.hashCode()) % suitableUsers.size();
        return suitableUsers.get(index);
    }
}